# -*- coding: utf-8 -*-
# created on 2016/05/17

# 求不含参数函数交点个数- 导数法 + 区间划分法 + Mathematica 求解法
# 求含参数函数交点个数 - Mathematica 求解法 + 特殊值法

from __future__ import division
from sympy import Union, S
from mathsolver.functions.base import (BasePieceFunc, BaseEq, BaseFunction, BaseNumber, BaseFunc, BaseSymbolValue,
                                       new_latex)
from mathsolver.functions.hanshu.dingyiyu import QiuDingYiYu
from mathsolver.functions.hanshu.helper import check_func, check_inter
from mathsolver.functions.hanshu.lingdian_geshu import LingDianGeShu


class _JiaoDianGeShuFenDuan(BaseFunction):
    """求分段函数 与 函数 交点个数

    输入
        args[0], args[1] BaseFunc, BasePiecefunc
        args[2] optional 区间
    """

    def solver(self, *args):
        # 如果给定特定区间，只考虑给定区间
        has_qujian_arg = False
        if len(args) == 3:
            qujian = check_inter(args[2])
            has_qujian_arg = True

        if isinstance(args[0], BasePieceFunc):
            piecefunc, func = args[:2]
        else:
            func, piecefunc = args[:2]
        self.steps.append(["", "考虑分段函数在每个分段上与函数 %s 的交点个数" % func.printing()])

        piecefunc_expr, func_expr, var = piecefunc.expression, func.expression, func.var

        # 计算每个分段上的交点个数，然后相加
        lingdian_collector = 0
        for _expr, _range in piecefunc_expr:
            if has_qujian_arg:
                _range = _range.intersect(qujian)

            lingdian_n = JiaoDianGeShu().solver(
                BaseFunc({'var': var, 'expression': _expr, 'type': '', 'name': 'f'}),
                func, _range).output[0].value

            lingdian_collector += lingdian_n
            self.steps.append(["", "在区间 %s 上，函数有 %s 个交点" % (new_latex(_range), lingdian_n)])

        self.steps.append(["", "综上所述，函数共有 %s 个交点" % lingdian_collector])
        self.output.append(BaseNumber(lingdian_collector))
        self.label.add("求分段函数与函数交点个数")
        return self


class JiaoDianGeShu(BaseFunction):
    """求函数交点个数（含参+不含参）

    1. 不含参函数- 导数法 + 区间划分法 + Mathematica 求解法
    2. 含参函数 - Mathematica 求解法 + 特殊值法

    输入：args[0] BaseEq 或者 BaseFunc 或者 BasePiecefunc
        args[1] optional 区间
    """
    canshu = None

    def solver(self, *args):
        # 分段函数与函数交点个数
        if isinstance(args[0], BasePieceFunc) or isinstance(args[1], BasePieceFunc):
            return _JiaoDianGeShuFenDuan().solver(*args)

        # 转化为求函数零点个数
        expr, qujian = self.cal_qujian(args)
        self.steps.append(["", "问题等价于求函数 %s 在区间 %s 上的零点个数" % (new_latex(expr), new_latex(qujian))])
        lingdian_solver = LingDianGeShu().solver(BaseEq(['y', expr]), qujian)
        self.steps.extend(lingdian_solver.steps)
        result = lingdian_solver.output[0].value

        # 含参数：
        if isinstance(result, dict):
            self.steps.append(["", "综上所述："])
            self.canshu = lingdian_solver.canshu
            for ct, interval in result.items():
                self.steps.append(["", "当 %s ∈ %s 时，两个函数有 %s 个交点" % (new_latex(self.canshu), new_latex(interval), ct)])
        # 不含参数：
        else:
            self.steps.append(["即：", "两个函数有 %s 个交点" % result])

        self.output = lingdian_solver.output
        self.label.add("含参数函数的交点")
        return self

    def cal_qujian(self, args):
        """计算 expr, 区间"""
        func1, func2 = check_func(args[0]), check_func(args[1])
        expr1, expr2, var = func1.expression, func2.expression, func1.var
        expr = expr1 - expr2
        # 计算区间
        qujian = S.Reals
        if len(args) == 3:
            qujian = check_inter(args[2])
        elif func1.dingyiyu:
            qujian = qujian.intersect(func1.dingyiyu)
        elif func2.dingyiyu:
            qujian = qujian.intersect(func2.dingyiyu)
        elif self.search(var):
            qujian = qujian.intersect(self.search(var))
        else:
            try:
                def1 = QiuDingYiYu().solver(func1)
                qujian = qujian.intersect(def1)
            except Exception:
                pass
            try:
                def2 = QiuDingYiYu().solver(func2)
                qujian = qujian.intersect(def2)
            except Exception:
                pass
        return expr, qujian


class JiaoDianGeShuQiuCan(BaseFunction):
    """071.函数图像交点个数求参数 - Mathematica 解

    输入：args[0], args[1] BaseEq 或者 BaseFunc
         args[2] BaseNumber optional
         args[3] "有","没有"
         args[4] optional 区间"""

    def solver(self, *args):

        if args[2]:
            number = args[2].sympify()
        elif "没有" in args[3]:
            number = "none"
        else:
            number = "all"

        if args[4]:
            jiaodian_solver = JiaoDianGeShu().solver(args[0], args[1], args[4])
        else:
            jiaodian_solver = JiaoDianGeShu().solver(args[0], args[1])

        self.steps.extend(jiaodian_solver.steps)
        canshu = jiaodian_solver.canshu
        result = jiaodian_solver.output[0].value

        if number == "all":
            output_result = Union(*result.values())
        elif number == "none":
            output_result = S.Reals - Union(*result.values())
        else:
            output_result = result[number]
        self.steps.append(["", "所以所求参数范围为：%s ∈ %s" % (new_latex(canshu), new_latex(output_result))])
        self.output.append(BaseSymbolValue({canshu: output_result}))
        self.label.add("函数图像交点个数求参数")
        return self


if __name__ == '__main__':
    pass
